package com.zycuse.nettyboot.NettyServer;


import com.zycuse.nettyboot.Config;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.Delimiters;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.CharsetUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.concurrent.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static java.lang.System.out;

@Slf4j
@Service
public class NettyServerService {
	private static final int PORT = Config.SERVER_PORT;
	private Channel channel ;
	private CountDownLatch countDownLatch;
	private String response;

//	public static void main(String[] args) {
//		  new NettyServerService().startNetty();
//	  }


	@PostConstruct
	public void startNetty() {
		ScheduledExecutorService scheduledThread = Executors.newSingleThreadScheduledExecutor();
		scheduledThread.schedule(() -> running(PORT), 1, TimeUnit.SECONDS);
	}

	public Channel getChannel() {
		return channel;
	}

	public void setChannel(Channel channel) {
		this.channel = channel;
	}


	public String sendRequest(String url) {
		if (this.channel!= null && this.channel.isActive()) {
			this.channel.writeAndFlush("<q_key_" + url + ">\n");
		}
//		Future<String> request = new FutureTask<String>(() ->{
//			return response;
//		});
		countDownLatch = new CountDownLatch(1);
		try {
			countDownLatch.await();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return response;
	}
	private void running(int port) {
		// EventLoopGroup是用来处理IO操作的多线程事件循环器
		// bossGroup 用来接收进来的连接
		EventLoopGroup bossGroup = new NioEventLoopGroup();
		// workerGroup 用来处理已经被接收的连接
		EventLoopGroup workerGroup = new NioEventLoopGroup();
		try {
			// 启动 NIO 服务的辅助启动类
			ServerBootstrap b = new ServerBootstrap();
			b.group(bossGroup, workerGroup)
					// 配置 Channel
					.channel(NioServerSocketChannel.class).childHandler(new InitServerChannel());
			// 绑定端口，开始接收进来的连接
			ChannelFuture f;
			f = b.bind(port).sync();
			f.channel().closeFuture().sync();
		} catch (InterruptedException e) {
			log.error(e.getMessage());
			// 等待服务器 socket 关闭 。
		} finally {
			workerGroup.shutdownGracefully();
			bossGroup.shutdownGracefully();
		}
	}

	public class InitServerChannel extends ChannelInitializer<Channel>{

		@Override
		protected void initChannel(Channel ch) throws Exception {
			ch.pipeline().addLast("spliter", new DelimiterBasedFrameDecoder(1024*1024, Delimiters.lineDelimiter()));
			ch.pipeline().addLast(new StringDecoder(CharsetUtil.UTF_8));
			ch.pipeline().addLast(new StringEncoder(CharsetUtil.UTF_8));
			ch.pipeline().addLast(new SimpleServerHandler());
		}
	}
	@ChannelHandler.Sharable
	private class SimpleServerHandler extends SimpleChannelInboundHandler<String> {
		/**
		 * 链接创建
		 */
		@Override
		public void channelActive(ChannelHandlerContext ctx) throws Exception {
			log.debug("上线了：" + "上线的是第:");
			channel = ctx.channel();
//			ctx.writeAndFlush("<q_key_https://www.baidu.com>\n123\n");
		}

		/**
		 * 链接断开
		 *
		 * @param ctx
		 * @throws Exception
		 */
		@Override
		public void channelInactive(ChannelHandlerContext ctx) throws Exception {
			channel = null;
			log.debug("掉线了：" + "掉线的是第:" );
		}

		/**
		 * 18:09:25 [nioEventLoopGroup-4-1] INFO  com.zjpavt.demo.action.TestClient Caller+0	 at com.zjpavt.demo.action.TestClient$1.getMessage(TestClient.java:47)
		 * - f21158585e1243b0ba443076c8859b72
		 * 心跳机制的处理
		 *
		 * @param ctx
		 * @param evt
		 * @throws Exception
		 */
		@Override
		public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
			if (evt instanceof IdleStateEvent) {
				IdleState state = ((IdleStateEvent) evt).state();
				switch (state) {
					case ALL_IDLE:
						break;
					case READER_IDLE:
						break;
					case WRITER_IDLE:
						break;
					default:
						break;
				}
			} else {
				super.userEventTriggered(ctx, evt);
			}
		}

		/**
		 * 处理异常状态
		 *
		 * @param ctx
		 * @param cause
		 * @throws Exception
		 */
		@Override
		public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
			/*log.error("异常关闭"+cause.getMessage());*/
			cause.printStackTrace();
		}

		/**
		 * 获取到的客户端的信息
		 *
		 * @param ctx
		 * @param msg
		 * @throws Exception
		 */
		@Override
		protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
			log.info("server recived message is :" + msg);
			String regexPower = "<([a-z])(_[^_]*)(_[^_]*)?(_[^_]*)?>";
			Pattern regexPattern = Pattern.compile(regexPower);
			Matcher matcher = regexPattern.matcher(msg);
			if (matcher.find()) {
				String regex1 = matcher.group(1);
				if (msg != null && msg.contains("<p_")) {
					if (!msg.endsWith("\n")) {
						msg = msg + "\n";
					}
					ctx.writeAndFlush(msg);
				}

				if ("q".equals(regex1)) {
					String regex2 = matcher.group(2).substring(1);
					String regex3 = matcher.group(3).substring(1);
					byte[] bytes = regex3.getBytes(CharsetUtil.UTF_8);
					String decodeMsg = new String(Base64.decodeBase64(bytes), CharsetUtil.UTF_8);
					response = decodeMsg;
					countDownLatch.countDown();
				}
			} else {
				log.info("unknow message: " + msg);
			}
		}
	}
}

